package com.jasonzqshen.ifm.project;

import java.lang.reflect.InvocationTargetException;
import java.net.URI;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ide.undo.CreateProjectOperation;
import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.misc.StatusUtil;
import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
import org.eclipse.ui.statushandlers.StatusAdapter;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.internal.wizards.newresource.*;

import com.jasonzqshen.ifm.utils.SystemLog;

/**
 * Project Creator
 * 
 * @author Jason
 * 
 */
@SuppressWarnings("restriction")
public class ProjectCreator {
    /**
     * Create Feature Modeling Project
     * 
     * @param projectName
     * @param uri
     * @return
     */
    public static IProject createFeatureModelProject(String projectName,
            URI uri, final Shell shell, IWizardContainer container) {
        IProject newProject = createBasicProject(projectName, uri, shell,
                container);
        FileCreator.CreateProjectFile(newProject, container, shell);
        return newProject;
    }

    /**
     * Create empty project
     * 
     * @param projectName
     * @param uri
     * @return
     */
    private static IProject createBasicProject(String projectName, URI uri,
            final Shell shell, IWizardContainer container) {
        final IProject newProjectHandle = ResourcesPlugin.getWorkspace()
                .getRoot().getProject(projectName);
        // get workspace
        IWorkspace workspace = ResourcesPlugin.getWorkspace();

        final IProjectDescription description = workspace
                .newProjectDescription(projectName);
        description.setLocationURI(uri);

        // create the new project operation
        IRunnableWithProgress op = new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor)
                    throws InvocationTargetException {
                CreateProjectOperation op = new CreateProjectOperation(
                        description, "New Project");
                try {
                    op.execute(monitor,
                            WorkspaceUndoUtil.getUIInfoAdapter(shell));
                } catch (ExecutionException e) {
                    SystemLog.logError(e.getMessage(), e);
                    throw new InvocationTargetException(e);
                }
            }
        };

        // run the new project creation operation
        try {
            container.run(true, true, op);
        } catch (InterruptedException e) {
            SystemLog.logError(e.getMessage(), e);
            return null;
        } catch (InvocationTargetException e) {
            SystemLog.logError(e.getMessage(), e);
            Throwable t = e.getTargetException();
            if (t instanceof ExecutionException
                    && t.getCause() instanceof CoreException) {
                handleCoreException(t, newProjectHandle);
            } else {
                StatusAdapter status = new StatusAdapter(new Status(
                        IStatus.WARNING, IDEWorkbenchPlugin.IDE_WORKBENCH, 0,
                        NLS.bind(ResourceMessages.NewProject_internalError,
                                t.getMessage()), t));
                status.setProperty(IStatusAdapterConstants.TITLE_PROPERTY,
                        ResourceMessages.NewProject_errorMessage);
                StatusManager.getManager().handle(status,
                        StatusManager.LOG | StatusManager.BLOCK);
            }
            return null;
        }
        return newProjectHandle;
    }

    /**
     * Handle Core Exception
     * 
     * @param t
     *            Exception
     */
    private static void handleCoreException(Throwable t, IProject newProject) {
        if (!(t instanceof ExecutionException && t.getCause() instanceof CoreException)) {
            return;
        }
        CoreException cause = (CoreException) t.getCause();
        StatusAdapter status;
        if (cause.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
            status = new StatusAdapter(StatusUtil.newStatus(IStatus.WARNING,
                    NLS.bind(
                            ResourceMessages.NewProject_caseVariantExistsError,
                            newProject.getName()), cause));
        } else {
            status = new StatusAdapter(StatusUtil.newStatus(cause.getStatus()
                    .getSeverity(), ResourceMessages.NewProject_errorMessage,
                    cause));
        }
        status.setProperty(IStatusAdapterConstants.TITLE_PROPERTY,
                ResourceMessages.NewProject_errorMessage);
        StatusManager.getManager().handle(status, StatusManager.BLOCK);
    }
}
